package server

import contextManager._
import scala.collection.mutable._

object Server extends Adaptable{	
	implicit def listToQueue(list:MutableList[Content]) = {
		val queue= new Queue[Content]
		for(x <- list){
			queue.enqueue(x)
		}
		queue
	}
	
	private var cache = new Queue[Content]
	
	def listContent = {
		for(x <- cache){
			print(x.getIdentifier)
			print("\t")
			print(x.getContent)
			if(x.isInstanceOf[CompressedContent]){
				println("(Compressed)")
			}
			else{
				println("")
			}
			}
	}
	
	var defaultAddImplementation = (content:Content) => {
		//Default implementations assumes no memory constraints
		println("SERVER: Default add implementation")
		if(cache.exists(c => content.getIdentifier == c.getIdentifier)){
			cache = cache.filterNot((c => content.getIdentifier == c.getIdentifier))
		}
		cache.enqueue(content)
	}
	
	var defaultLookupImplementation = (key:String) => {
		println("SERVER: Default lookup implementation")
		val results = cache.filter((c => key == c.getIdentifier))
		if(!results.isEmpty){
			networkOutput(results.head.getContent)
		}
		else{
		 ""
		}
		}
	
	var defaultDeleteImplementation = (key:String) => {
		//Default implementations assumes no memory constraints
		println("SERVER: Default delete implementation")
		if(cache.exists(c => key == c.getIdentifier)){
			cache = cache.filterNot((c => key == c.getIdentifier))
		}
	}
	
	var defaultNetworkOutput = (content:String) => {content}


	var add	   = defaultAddImplementation
	var delete = defaultDeleteImplementation
	var lookup = defaultLookupImplementation
	var networkOutput = defaultNetworkOutput

	override def setup():Unit = {
		super.setup()
		
		/* Default implementation */
		var defaultActivationFunction = (c:Context) => {c.memoryUsage < 50}
		ContextManager registerListener( 
				"add",
				defaultActivationFunction,
				defaultLookupImplementation
				)

		ContextManager registerListener( 
				"lookup",
				defaultActivationFunction,
				defaultLookupImplementation
				)
		
		/* Compressing implementation */
		var compressionActivationFunction = (c:Context) => {c.cpuUsage < 50 & c.memoryUsage >= 50}
		ContextManager registerListener( 
				"add",
				compressionActivationFunction,
				(content:Content) => {
					//Default implementations assumes no memory constraints
					println("SERVER: Compressing add implementation")
					if(cache.exists(c => content.getIdentifier == c.getIdentifier)){
						 cache = cache.filterNot((c => content.getIdentifier == c.getIdentifier))
					}
					cache.enqueue(new CompressedContent(content.getIdentifier, content.getContent ))
				}
				)

		ContextManager registerListener( 
				"lookup",
				compressionActivationFunction,
				(key:String) =>{
					println("SERVER: Compressing lookup implementation")
					val results = cache.filter((c => key == c.getIdentifier))
					if(!results.isEmpty){
						//Compressing uncompressed items
						var container = results.head;
						if(!container.isInstanceOf[CompressedContent]){
							var uncompressedContent = new Content(container.getIdentifier,container.getContent)
							Server.add(uncompressedContent)
						}
						networkOutput(results.head.getContent)
					}
					else{
		 				""
					}
					}
				)
		
		/* Limiting implementation */
		var limitingActivationFunction = (c:Context) => {c.cpuUsage >= 50 & c.memoryUsage >= 50}
		ContextManager registerListener( 
				"add",
				limitingActivationFunction,
				(content:Content) => {
					var maxEntries = 3
					//Default implementations assumes no memory constraints
					println("SERVER: Memory limiting add implementation")
					if(cache.exists(c => content.getIdentifier == c.getIdentifier)){
						 cache = cache.filterNot((c => content.getIdentifier == c.getIdentifier))
					}
					cache.enqueue(content)
					if(cache.size - maxEntries > 0){
						cache = cache.drop(cache.size - maxEntries)
					}
				}
				)
				
		ContextManager registerListener( 
				"lookup",
				limitingActivationFunction,
				defaultLookupImplementation
				)
		
		/* Network compression */
		var defaultNetworkActivationFunction = (c:Context) => {c.networkUsage < 50}
		ContextManager registerListener( 
				"networkOutput",
				defaultNetworkActivationFunction,
				defaultNetworkOutput
				)


		var networkCompressionActivationFunction = (c:Context) => {c.networkUsage >= 50}
		ContextManager registerListener( 
				"networkOutput",
				networkCompressionActivationFunction,
				(content:String) => {
					println("SERVER: Compressing network output")
					CompressedContent.compressData(content)
				}
				)
	}
}